package cn.ug.pay.service.impl;

import cn.ug.account.bean.DataDictionaryBean;
import cn.ug.analyse.bean.request.MemberAnalyseMsgParamBean;
import cn.ug.bean.LoginBean;
import cn.ug.bean.base.SerializeObject;
import cn.ug.bean.type.ResultType;
import cn.ug.config.FundRateConfig;
import cn.ug.config.RedisGlobalLock;
import cn.ug.config.YeePayConfig;
import cn.ug.core.SerializeObjectError;
import cn.ug.core.ensure.Ensure;
import cn.ug.core.login.LoginHelper;
import cn.ug.enums.PayTypeEnum;
import cn.ug.enums.RateKeyEnum;
import cn.ug.enums.WxTemplateEnum;
import cn.ug.feign.*;
import cn.ug.mall.bean.FeeBean;
import cn.ug.mall.bean.GoodsSkuBean;
import cn.ug.mall.bean.MemberGoodsOrderDetailBean;
import cn.ug.mall.bean.OrderBean;
import cn.ug.msg.bean.type.SmsType;
import cn.ug.msg.mq.Msg;
import cn.ug.msg.mq.Sms;
import cn.ug.msg.mq.WxMessageParamBean;
import cn.ug.msg.mq.WxNotifyData;
import cn.ug.pay.bean.BillBean;
import cn.ug.pay.bean.BillGoldBean;
import cn.ug.pay.bean.ProductOrderBean;
import cn.ug.pay.bean.WithdrawAuditBean;
import cn.ug.pay.bean.request.PayParamBean;
import cn.ug.pay.bean.request.RechargeParamBean;
import cn.ug.pay.bean.request.TradeCommonParamBean;
import cn.ug.pay.bean.request.YeePayParamBean;
import cn.ug.pay.bean.response.BankCardBean;
import cn.ug.pay.bean.response.BankInfoBean;
import cn.ug.pay.bean.status.CommonConstants;
import cn.ug.pay.bean.status.PayDistributePrefix;
import cn.ug.pay.bean.status.TbillStatusEnum;
import cn.ug.pay.bean.status.TradeStatus;
import cn.ug.pay.bean.type.*;
import cn.ug.pay.component.PayCommon;
import cn.ug.pay.component.YeePayCommons;
import cn.ug.pay.mapper.*;
import cn.ug.pay.mapper.entity.*;
import cn.ug.pay.mq.WithdrawMQ;
import cn.ug.pay.pay.yeepay.TZTService;
import cn.ug.pay.service.*;
import cn.ug.pay.utils.RequestUtil;
import cn.ug.product.bean.response.ProductFindBean;
import cn.ug.service.impl.BaseServiceImpl;
import cn.ug.util.BigDecimalUtil;
import cn.ug.util.DateUtils;
import cn.ug.util.SerialNumberWorker;
import cn.ug.util.UF;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.dozer.DozerBeanMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

import static cn.ug.config.QueueName.*;
import static cn.ug.util.ConstantUtil.GOLD_WEIGHT_RANGE;


@Service
public class TradeServiceImpl extends BaseServiceImpl implements TradeService {
    @Autowired
    private FundRateConfig fundRateConfig;
    @Resource
    private BillService billService;
    @Resource
    private MemberUserService memberUserService;
    @Resource
    private ProductOrderFeeMapper productOrderFeeMapper;
    @Resource
    private WithdrawService withdrawService;
    @Autowired
    private CouponRepertoryService couponRepertoryService;
    @Resource
    private ProductOrderService productOrderService;

    @Resource
    private MallGoodsOrderService mallGoodsOrderService;
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Resource
    private YeePayCommons yeePayCommons;
    @Resource
    private PayCommon payCommon;
    @Resource
    private TradeMapper tradeMapper;

    @Resource
    private BankCardMapper bankCardMapper;

    @Resource
    private MemberAccountMapper memberAccountMapper;

    @Resource
    private BankInfoMapper bankInfoMapper;

    @Resource
    private AmqpTemplate amqpTemplate;

    @Resource
    private RedisGlobalLock redisGlobalLock;

    @Resource
    private YeePayConfig yeePayConfig;

    @Resource
    private TZTService tZTService;
    @Autowired
    private RateSettingsService rateSettingsService;
    @Resource
    private RequestUtil requestUtil;
    @Autowired
    private DataDictionaryService dataDictionaryService;
    @Autowired
    private ProductService productService;
    @Autowired
    private MemberGoldMapper memberGoldMapper;
    @Resource
    private MemberAccountService memberAccountService;
    @Autowired
    private PriceService priceService;
    @Resource
    private DozerBeanMapper dozerBeanMapper;
    @Autowired
    private BillGoldService billGoldService;
    @Autowired
    private OrderService orderService;
    @Autowired
    private BillMapper billMapper;
    @Autowired
    private PayTbillMapper payTbillMapper;
    @Autowired
    private PayTbillService payTbillService;
    //每日最高可购克重
    private static final String BUY_MAX_GRAM_PERDAY = "buyMaxGramPerDay";


    private static Logger logger = LoggerFactory.getLogger(TradeServiceImpl.class);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int save(Trade trade) {
        if(null == trade || StringUtils.isBlank(trade.getMemberId())) {
            Ensure.that(true).isTrue("00000002");
        }
        if(StringUtils.isBlank(trade.getId())) {
            trade.setId(UF.getRandomUUID());
        }
        if(StringUtils.isBlank(trade.getOrderId())) {
            trade.setOrderId(SerialNumberWorker.getInstance().nextId());
        }
        int rows = tradeMapper.insert(trade);
        Ensure.that(rows).isLt(1,"00000005");
        return 0;
    }

    /**
     * 充值请求
     *
     * @param rechargeParamBean
     * @return
     */
    @Transactional
    @Override
    public String recharge(RechargeParamBean rechargeParamBean) {
        LoginBean loginBean = LoginHelper.getLoginBean();
        String orderId = null;
        // 1、获取分布式锁防止重复调用 锁定时间为5秒=====================================================
        String rechargeSubmitKey = PayDistributePrefix.PAY_RECHARGE_SUBMIT + loginBean.getId();
        if (redisGlobalLock.lock(rechargeSubmitKey, CommonConstants.PAY_ORDER_SUBMIT_LOCK_TIME, TimeUnit.MILLISECONDS)) {
            try {
                //根据绑定银行卡获取银行卡相关信息
                //BankCard bankCard = bankCardMapper.findById(rechargeParamBean.getBankCardId());
                BankCard bankCard = bankCardMapper.findDefaultByMemberId(loginBean.getId());
                Ensure.that(bankCard == null).isTrue("17000410");
                Ensure.that(CommonConstants.BankCardStatus.YES_BIND.getIndex() == bankCard.getStatus()).isFalse("17000410");  //验证该银行卡以否已绑定

                //验证银行是否维护中
                BankInfoBean bankInfo = bankInfoMapper.queryBankInfo(bankCard.getBankCode());
                if (bankInfo != null && CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()) {
                    Msg msg = new Msg();
                    msg.setMemberId(loginBean.getId());
                    msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.BANK_MAINTENANCE.getIndex());
                    Map<String, String> paramMap = new HashMap<>();
                    paramMap.put("bankName",  cn.ug.util.StringUtils.sensitivityBankCard(bankCard.getCardNo()));
                    msg.setParamMap(paramMap);
                    amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
                    Ensure.that(CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()).isTrue("17000423");
                }

                //生成商户流水号
                orderId = SerialNumberWorker.getInstance().nextId();
                //获取银行基础信息
                BankCardBean bankCardBean = dozerBeanMapper.map(bankCard, BankCardBean.class);

                SerializeObject rateBean  = rateSettingsService.get(RateKeyEnum.RECHARGE.getKey());
                BigDecimal fee = BigDecimal.ZERO;
                if (rateBean != null && rateBean.getData() != null) {
                    JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
                    BigDecimal minAmount = json.getBigDecimal("minAmount");
                    if (minAmount != null && rechargeParamBean.getAmount().compareTo(minAmount) < 0) {
                        Ensure.that(0).isLt(1, "17002040");
                    }
                    int dayNum = billMapper.getTransactionNumForThisDay(loginBean.getId(), CommonConstants.PayType.RECHARGE.getIndex());
                    int monthNum = billMapper.getTransactionNumForThisMonth(loginBean.getId(), CommonConstants.PayType.RECHARGE.getIndex());
                    fee = fundRateConfig.getFee(json, rechargeParamBean.getAmount(), dayNum, monthNum);
                }

                //生成充值订单号
                Trade trade = dozerBeanMapper.map(rechargeParamBean, Trade.class);
                trade.setId(UF.getRandomUUID());
                trade.setMemberId(loginBean.getId());
                trade.setOrderId(orderId);
                trade.setSerialNumber(orderId);
                trade.setTitle(CommonConstants.RECHARGE);
                trade.setStatus(CommonConstants.PayStatus.NEW.getIndex());  //处理中
                trade.setPayWay(CommonConstants.PayWay.YEE_PAY.getIndex());
                trade.setType(CommonConstants.PayType.RECHARGE.getIndex());
                trade.setAmount(rechargeParamBean.getAmount());
                BigDecimal amount = BigDecimalUtil.to2Point(rechargeParamBean.getAmount().add(fee));
                trade.setPayAmount(amount);
                trade.setFee(fee);
                trade.setBankCardId(bankCardBean.getId());
                int num = tradeMapper.insert(trade);

                //设置公共参数
                TradeCommonParamBean paramBean = new TradeCommonParamBean();
                paramBean.setOrderId(orderId);
                paramBean.setAmount(amount);
                paramBean.setTitle(CommonConstants.RECHARGE);
                paramBean.setBankCardBean(bankCardBean);
                paramBean.setCallBackUrl(yeePayConfig.getRechargeCallBackUrl());
                //组装
                TreeMap<String, String> dataMap = requestUtil.getRequestParam(paramBean);
                logger.info("---支付充值请求参数---" + dataMap.toString());
                //发起请求
                Map<String, String> map = requestUtil.sendYeePayHttp(yeePayConfig.getUnSendBindPayRequestURL(), dataMap);
                logger.info("----支付充值相应参数----" + map);
                if (map != null && !map.isEmpty()) {
                    if (map.containsKey("status")) {
                        String status = String.valueOf(map.get("status"));
                        Trade trades = new Trade();
                        trades.setSerialNumber(orderId);
                        //处理中
                        if ("PROCESSING".equals(status)) {
                            //保存记录
                            trades.setStatus(CommonConstants.PayStatus.PROCESSING.getIndex());
                            //系统异常
                        } else if ("FAIL".equals(status)) {
                            trades.setStatus(CommonConstants.PayStatus.EXCEPTION.getIndex());
                            //失败
                        } else {
                            logger.info("-----充值失败-----status=" + status + "-----errormsg" + map.get("errormsg"));
                            //提示用户充值失败
                            Ensure.that(true).isTrue(map.get("errormsg"));
                        }
                        tradeMapper.updatePayStatus(trades);
                    } else {
                        //提示错误原因
                        Ensure.that(true).isTrue(map.get("customError"));
                    }
                }
            } finally {
                // 4、释放分布式锁 ================================================================
                redisGlobalLock.unlock(rechargeSubmitKey);
            }
        } else {
            // 如果没有获取锁
            logger.info("-------没有获取到锁-------");
            Ensure.that(true).isTrue("17000706");
        }

        return orderId;
    }

    @Override
    public boolean notifyForSuccess(String orderId, String thirdNumber) {
        if (StringUtils.isNotBlank(orderId)) {
            Trade trade = tradeMapper.queryTradeByOrderId(orderId);
            Ensure.that(trade == null).isTrue("00000005");
            if(trade.getStatus() != CommonConstants.PayStatus.YESPAY.getIndex()) {
                Trade trades = new Trade();
                trades.setSerialNumber(orderId);
                trades.setThirdNumber(thirdNumber);
                trades.setStatus(CommonConstants.PayStatus.YESPAY.getIndex());

                MemberAccount memberAccount = null;
                // 1、获取分布式锁防止重复调用 =====================================================
                String key = PayDistributePrefix.PAY_MEMBER_ACCOUNT + trade.getMemberId();
                if (redisGlobalLock.lock(key)) {
                    try {
                        memberAccount = memberAccountMapper.findByMemberId(trade.getMemberId());
                        if(memberAccount != null){
                            Map<String,Object> memberAccountMap = new HashMap<String,Object>();
                            memberAccountMap.put("id",   memberAccount.getId());
                            memberAccountMap.put("fundAmount", memberAccount.getFundAmount().add(trade.getAmount()).toString());
                            memberAccountMap.put("usableAmount",memberAccount.getUsableAmount().add(trade.getAmount()).toString());
                            int rows = memberAccountMapper.updateByPrimaryKeySelective(memberAccountMap);
                            if (rows < 1) {
                                Ensure.that(true).isTrue("17000706");
                            }
                        } else {
                            return false;
                        }

                    } finally {
                        redisGlobalLock.unlock(key);
                    }
                } else {
                    Ensure.that(true).isTrue("17000706");
                }

                //更新收入明细
                BillBean billBean = new BillBean();
                billBean.setOrderId(trade.getOrderId());
                billBean.setMemberId(trade.getMemberId());
                billBean.setAmount(trade.getPayAmount());
                billBean.setActualAmount(trade.getPayAmount().subtract(trade.getFee()));
                billBean.setFee(trade.getFee());
                billBean.setType(BillType.INCOME.getValue());
                billBean.setTradeType(TradeType.EBANK_RECHARGE.getValue());
                billService.save(billBean);

                if (billBean.getFee() != null && billBean.getFee().doubleValue() > 0) {
                    billBean.setId(UF.getRandomUUID());
                    billBean.setTradeType(TradeType.RECHARGE_FEE.getValue());
                    billBean.setAmount(billBean.getFee());
                    billBean.setActualAmount(billBean.getFee());
                    billBean.setFee(BigDecimal.ZERO);
                    billBean.setType(BillType.OUTLAY.getValue());
                    billService.save(billBean);
                }

                //充值成功提醒
                Msg msg = new Msg();
                msg.setMemberId(trade.getMemberId());
                msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.RECHARGE.getIndex());

                Map<String, String> paramMap = new HashMap<>();
                paramMap.put("date", UF.getFormatDate("MM月dd日", UF.getDateTime()));
                paramMap.put("amount", trade.getAmount() + "");
                paramMap.put("usableAmount", memberAccount.getUsableAmount().add(trade.getAmount()) + "");
                paramMap.put("whetherPush", "YES");
                msg.setParamMap(paramMap);

                amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);

                //统计分析成功
                MemberAnalyseMsgParamBean analyse = new MemberAnalyseMsgParamBean();
                analyse.setMemberId(trade.getMemberId());
                analyse.setType(cn.ug.analyse.bean.status.CommonConstants.MemberAnalyseType.RECHARGE.getIndex());
                amqpTemplate.convertAndSend(QUEUE_MEMBER_ANALYSE, analyse);

                WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
                wxMessageParamBean.setMemberId(trade.getMemberId());
                wxMessageParamBean.setType(WxTemplateEnum.SUFFICIENT_NOT_RICH.getType());
                WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.SUFFICIENT_NOT_RICH.getType());
                WxNotifyData wxNotifyData = new WxNotifyData();

                Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
                WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
                first.setDataValue(wxTemplateEnum.getFirstData());
                wxParamMap.put("first", first);

                WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
                keyword1.setDataValue(trade.getAmount().toString());
                wxParamMap.put("keyword1", keyword1);

                WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
                keyword2.setDataValue(DateUtils.dateToStr(new Date(), DateUtils.patter));
                wxParamMap.put("keyword2", keyword2);

                WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
                keyword3.setDataValue(memberAccount.getFundAmount().add(trade.getAmount()) + "");
                wxParamMap.put("keyword3", keyword3);

                WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
                remark.setDataValue(wxTemplateEnum.getRemark());
                wxParamMap.put("remark", remark);

                wxNotifyData.setData(wxParamMap);
                wxMessageParamBean.setTemplateData(wxNotifyData);
                amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
            }
            int rows = tradeMapper.updatePayStatus(trade);
            if (rows < 1) {
                Ensure.that(true).isTrue("00000005");
            }
            return true;
        }
        return false;
    }

    /**
     * 充值异步回调
     *
     * @param yeePayParamBean
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String yeePayRechargeAsyNotify(YeePayParamBean yeePayParamBean) {
        return yeePayCommons.yeePayRechargeAsyNotify(yeePayParamBean);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SerializeObject pay(String memberId, GoodsSkuBean goodsSkuBean, int quantity, int type, long addressId, FeeBean feeBean, String cellphone, int source) {
        String orderSubmitKey = PayDistributePrefix.PAY_ORDER_SUBMIT + memberId;
        // 2、获取分布式锁进行对账户锁定 =====================================================
        if (redisGlobalLock.lock(orderSubmitKey, CommonConstants.PAY_ORDER_SUBMIT_LOCK_TIME, TimeUnit.MILLISECONDS)) {
            try {
                MemberGold memberGold = memberGoldMapper.findByMemberId(memberId);
                if (null == memberGold || StringUtils.isBlank(memberGold.getMemberId())) {
                    return new SerializeObjectError("00000102");
                }

                // 可用资产 = (T-1日利息) + T日本金 + (T-1日本金)
                BigDecimal usableAmount = BigDecimalUtil.adds(memberGold.getInterestHistoryAmount(), memberGold.getPrincipalNowAmount(), memberGold.getPrincipalHistoryAmount());
                BigDecimal usableGam = BigDecimalUtil.to5Point(usableAmount);
                double payWeight = goodsSkuBean.getGram().doubleValue() * quantity;
                if (usableGam == null || usableGam.doubleValue() < payWeight) {
                    return new SerializeObjectError("17002022");
                }
                BigDecimal totalGam = new BigDecimal(payWeight);
                BankCard bankCard = bankCardMapper.findDefaultByMemberId(memberId);
                Ensure.that(bankCard == null).isTrue("17000419");
                MemberAccount memberAccount = memberAccountMapper.findByMemberId(memberId);
                Ensure.that(memberAccount == null).isTrue("00000003");

                String orderId = SerialNumberWorker.getInstance().nextId();
                Trade trade = new Trade();
                trade.setAmount(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee()));
                trade.setBankCardId(bankCard.getId());
                trade.setId(UF.getRandomUUID());
                trade.setFee(BigDecimal.ZERO);
                trade.setMemberId(memberId);
                trade.setOrderId(orderId);
                trade.setTitle(feeBean.getName());
                trade.setPayWay(1);
                trade.setSerialNumber(orderId);
                if (memberAccount.getUsableAmount().compareTo(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())) < 0) {
                    BigDecimal payAmount = BigDecimalUtil.to2Point(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee()).subtract(memberAccount.getUsableAmount()));   //银行卡实际支付金额
                    trade.setPayAmount(payAmount);
                }
                trade.setStatus(CommonConstants.PayStatus.PROCESSING.getIndex());
                if (type == PayTypeEnum.GOLD_EXTRACTION.getType()) {
                    trade.setType(PayTypeEnum.GOLD_EXTRACTION.getType());
                } else if (type == PayTypeEnum.GOLD_CHANGE.getType()) {
                    trade.setType(PayTypeEnum.GOLD_CHANGE.getType());
                }
                tradeMapper.insert(trade);
                BigDecimal[] payAmount = new BigDecimal[4];
                payAmount[0] = totalGam;
                payAmount[1] = BigDecimal.ZERO;
                payAmount[2] = BigDecimal.ZERO;
                payAmount[3] = BigDecimal.ZERO;

                // 扣除 T-1日利息 ===========================================================
                if (totalGam.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal interestHistoryAmount = memberGold.getInterestHistoryAmount();
                    if (interestHistoryAmount.compareTo(totalGam) >= 0) {
                        interestHistoryAmount = BigDecimalUtil.subtract(interestHistoryAmount, totalGam);
                        memberGold.setInterestHistoryAmount(interestHistoryAmount);
                        payAmount[1] = totalGam;
                        totalGam = BigDecimal.ZERO;
                    } else {
                        memberGold.setInterestHistoryAmount(BigDecimal.ZERO);
                        payAmount[1] = interestHistoryAmount;
                        totalGam = BigDecimalUtil.subtract(totalGam, interestHistoryAmount);
                    }
                }

                // 扣除 T日本金 =============================================================
                if (totalGam.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal principalNowAmount = memberGold.getPrincipalNowAmount();
                    if (principalNowAmount.compareTo(totalGam) >= 0) {
                        principalNowAmount = BigDecimalUtil.subtract(principalNowAmount, totalGam);
                        memberGold.setPrincipalNowAmount(principalNowAmount);
                        payAmount[2] = totalGam;
                        totalGam = BigDecimal.ZERO;
                    } else {
                        memberGold.setPrincipalNowAmount(BigDecimal.ZERO);
                        payAmount[2] = principalNowAmount;

                        totalGam = BigDecimalUtil.subtract(totalGam, principalNowAmount);
                    }
                }

                //  扣除 T-1日本金 ===========================================================
                if (totalGam.compareTo(BigDecimal.ZERO) > 0) {
                    BigDecimal principalHistoryAmount = memberGold.getPrincipalHistoryAmount();
                    if (principalHistoryAmount.compareTo(totalGam) >= 0) {
                        principalHistoryAmount = BigDecimalUtil.subtract(principalHistoryAmount, totalGam);
                        memberGold.setPrincipalHistoryAmount(principalHistoryAmount);
                        payAmount[3] = totalGam;
                        totalGam = BigDecimal.ZERO;
                    } else {
                        memberGold.setPrincipalHistoryAmount(BigDecimal.ZERO);
                        payAmount[3] = principalHistoryAmount;
                        totalGam = BigDecimalUtil.subtract(totalGam, principalHistoryAmount);
                    }
                }
                if (!BigDecimalUtil.isZeroOrNull(totalGam)) {
                    return new SerializeObjectError("17002022");
                }
                int orderType = 2;
                if (type == PayTypeEnum.GOLD_CHANGE.getType()) {
                    orderType = 3;
                }
                // 余额支付
                if (memberAccount.getUsableAmount().compareTo(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())) >= 0) {
                    SerializeObject orderResult = orderService.pay(memberId, orderId, quantity, goodsSkuBean.getId(), cellphone, new BigDecimal(feeBean.getFreight()),
                            new BigDecimal(feeBean.getProcessFee()), orderType, 1, 3, addressId,
                            source, payAmount[1], payAmount[2], payAmount[3], BigDecimal.ZERO);
                    if (orderResult == null || orderResult.getCode() != ResultType.NORMAL) {
                        return new SerializeObjectError("00000005");
                    }
                    memberGold.setInterestAmount(memberGold.getInterestHistoryAmount());
                    memberGold.setPrincipalAmount(BigDecimalUtil.adds(memberGold.getPrincipalNowAmount(), memberGold.getPrincipalHistoryAmount()));
                    memberGold.setUsableAmount(BigDecimalUtil.adds(memberGold.getPrincipalAmount(), memberGold.getInterestAmount()));
                    memberGold.setTotalAmount(BigDecimalUtil.adds(memberGold.getUsableAmount(), memberGold.getFreezeAmount()));
                    memberGold.setTurnOutAmount(BigDecimalUtil.adds(memberGold.getTurnOutAmount(), payAmount[0]));
                    int rows = memberGoldMapper.update(memberGold);
                    if (rows < 1) {
                        // 提金/换金状态更换为失败
                        orderService.fail(orderId, "");
                        Ensure.that(true).isTrue("00000005");
                    }
                    // 抛出异常时，将提金/换金订单标记成失败
                    BillGoldBean billGoldBean = new BillGoldBean();
                    billGoldBean.setMemberId(memberId);
                    billGoldBean.setAmount(payAmount[0]);
                    billGoldBean.setFee(BigDecimal.ZERO);
                    billGoldBean.setActualAmount(BigDecimalUtil.subtract(billGoldBean.getAmount(), billGoldBean.getFee()));
                    SerializeObject priceBean = priceService.currentGoldPrice();
                    BigDecimal goldPrice = BigDecimal.ZERO;
                    if (priceBean != null && priceBean.getData() != null) {
                        goldPrice = new BigDecimal(priceBean.getData().toString());
                    }
                    billGoldBean.setGoldPrice(goldPrice);
                    billGoldBean.setType(BillGoldType.OUTLAY.getValue());
                    if (type == PayTypeEnum.GOLD_EXTRACTION.getType()) {
                        billGoldBean.setTradeType(BillGoldTradeType.EXTRACT_GOLD.getValue());
                    } else if (type == PayTypeEnum.GOLD_CHANGE.getType()) {
                        billGoldBean.setTradeType(BillGoldTradeType.CHANGE_GOLD.getValue());
                    }
                    billGoldService.save(billGoldBean);
                    BigDecimal fundAmount = BigDecimalUtil.to2Point(memberAccount.getFundAmount().subtract(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())));
                    BigDecimal usableMoney = BigDecimalUtil.to2Point(memberAccount.getUsableAmount().subtract(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())));
                    //扣除账户余额
                    Map<String, Object> param = new HashMap<String, Object>();
                    param.put("id", memberAccount.getId());
                    param.put("fundAmount", fundAmount);
                    param.put("usableAmount", usableMoney);
                    int updateResult = memberAccountMapper.updateByPrimaryKeySelective(param);
                    if (updateResult < 1) {
                        // 提金/换金状态更换为失败
                        orderService.fail(orderId, "");
                        Ensure.that(true).isTrue("00000005");
                    }

                    trade.setStatus(CommonConstants.PayStatus.YESPAY.getIndex());
                    tradeMapper.updatePayStatus(trade);

                    BillBean billBean = new BillBean();
                    billBean.setType(BillType.OUTLAY.getValue());
                    billBean.setMemberId(memberId);
                    billBean.setOrderId(orderId);
                    billBean.setAmount(new BigDecimal(feeBean.getFreight()));
                    billBean.setActualAmount(new BigDecimal(feeBean.getFreight()));
                    billBean.setFee(BigDecimal.ZERO);
                    billBean.setGoldPrice(goldPrice);
                    if (type == PayTypeEnum.GOLD_EXTRACTION.getType()) {
                        billBean.setTradeType(TradeType.GOLD_EXTRACTION_FREIGHT.getValue());
                        billService.save(billBean);
                        billBean.setAmount(new BigDecimal(feeBean.getProcessFee()));
                        billBean.setActualAmount(new BigDecimal(feeBean.getProcessFee()));
                        billBean.setFee(BigDecimal.ZERO);
                        billBean.setTradeType(TradeType.GOLD_EXTRACTION_PROCESS_COST.getValue());
                        billService.save(billBean);
                    } else if (type == PayTypeEnum.GOLD_CHANGE.getType()) {
                        billBean.setTradeType(TradeType.CHANGE_GOLD_FREIGHT.getValue());
                        billService.save(billBean);
                        billBean.setAmount(new BigDecimal(feeBean.getProcessFee()));
                        billBean.setActualAmount(new BigDecimal(feeBean.getProcessFee()));
                        billBean.setFee(BigDecimal.ZERO);
                        billBean.setTradeType(TradeType.CHANGE_GOLD_PROCESS_COST.getValue());
                        billService.save(billBean);
                    }

                    //提金/换金成功
                    //增加账户余额变动消息队列
                    payCommon.accountChangeMsgQueue(memberId, cn.ug.msg.bean.status.CommonConstants.MsgType.ACCOUNT_PAY_CHANGE.getIndex(),
                            BigDecimalUtil.to2Point(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())).toString(), fundAmount.toString());

                    Msg msg = new Msg();
                    msg.setMemberId(memberId);
                    msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.MALL_PAY_SUCCESS.getIndex());
                    Map<String, String> paramMap = new HashMap<>();
                    paramMap.put("goodsName", feeBean.getName());
                    paramMap.put("fundAmount", fundAmount.toString());
                    msg.setParamMap(paramMap);
                    amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);

                    /**
                     * 微信服务号消息推送  资金变动
                     */
                    WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
                    wxMessageParamBean.setMemberId(trade.getMemberId());
                    //消息推送类型
                    wxMessageParamBean.setType(WxTemplateEnum.FUND_CHANGE.getType());
                    WxTemplateEnum wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.FUND_CHANGE.getType());
                    WxNotifyData wxNotifyData = new WxNotifyData();

                    Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
                    WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
                    first.setDataValue(wxTemplateEnum.getFirstData());
                    wxParamMap.put("first", first);

                    WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
                    keyword1.setDataValue(cn.ug.msg.bean.status.CommonConstants.MsgType.MALL_PAY_SUCCESS.getName());
                    wxParamMap.put("keyword1", keyword1);

                    WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
                    keyword2.setDataValue(BigDecimalUtil.to2Point(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee())).toString());
                    wxParamMap.put("keyword2", keyword2);

                    WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
                    keyword3.setDataValue(DateUtils.dateToStr(new Date(),DateUtils.patter));
                    wxParamMap.put("keyword3", keyword3);

                    WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
                    keyword4.setDataValue(BigDecimalUtil.to2Point(usableMoney).toString());
                    wxParamMap.put("keyword4", keyword4);

                    WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
                    remark.setDataValue(wxTemplateEnum.getRemark());
                    wxParamMap.put("remark", remark);

                    wxNotifyData.setData(wxParamMap);
                    wxMessageParamBean.setTemplateData(wxNotifyData);
                    amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);

                    return new SerializeObject<>(ResultType.NORMAL, "00000001", orderId);
                } else {
                    BankInfoBean bankInfo = bankInfoMapper.queryBankInfo(bankCard.getBankCode());
                    if (bankInfo != null && CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()) {
                        Msg msg = new Msg();
                        msg.setMemberId(memberId);
                        msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.BANK_MAINTENANCE.getIndex());
                        Map<String, String> paramMap = new HashMap<>();
                        paramMap.put("bankName",  cn.ug.util.StringUtils.sensitivityBankCard(bankCard.getCardNo()));
                        msg.setParamMap(paramMap);
                        amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
                        Ensure.that(CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()).isTrue("17000423");
                    }
                    BankCardBean bankCardBean = dozerBeanMapper.map(bankCard, BankCardBean.class);
                    TradeCommonParamBean entity = new TradeCommonParamBean();
                    entity.setTitle(feeBean.getName());
                    entity.setMemberId(memberId);
                    entity.setOrderId(orderId);
                    BigDecimal itemAmount = BigDecimalUtil.to2Point(new BigDecimal(feeBean.getFreight() + feeBean.getProcessFee()));
                    BigDecimal fee = BigDecimal.ZERO;
                    SerializeObject rateBean  = rateSettingsService.get(RateKeyEnum.RECHARGE.getKey());
                    if (rateBean != null && rateBean.getData() != null) {
                        JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
                        int dayNum = billMapper.getTransactionNumForThisDay(memberId, CommonConstants.PayType.RECHARGE.getIndex());
                        int monthNum = billMapper.getTransactionNumForThisMonth(memberId, CommonConstants.PayType.RECHARGE.getIndex());
                        fee = fundRateConfig.getFee(json, itemAmount.subtract(memberAccount.getUsableAmount()), dayNum, monthNum);
                    }
                    itemAmount = BigDecimalUtil.to2Point(itemAmount.add(fee));
                    entity.setAmount(itemAmount);
                    entity.setAmount(BigDecimalUtil.to2Point(itemAmount.subtract(memberAccount.getUsableAmount())));
                    entity.setBankCardBean(bankCardBean);
                    entity.setBankCardBean(bankCardBean);
                    entity.setPayAmount(itemAmount);
                    entity.setType(type);
                    // 易宝支付
                    SerializeObject orderResult = orderService.pay(memberId, orderId, quantity, goodsSkuBean.getId(), cellphone, new BigDecimal(feeBean.getFreight()),
                            new BigDecimal(feeBean.getProcessFee()), orderType, 1, 6, addressId,
                            source, payAmount[1], payAmount[2], payAmount[3], BigDecimal.ZERO);
                    if (orderResult == null || orderResult.getCode() != ResultType.NORMAL) {
                        return new SerializeObjectError("00000005");
                    }


                    Map<String, Object> resultMap = yeePayCommons.prepayOrder(entity);
                    if (resultMap == null || resultMap.isEmpty()) {
                        memberGold.setInterestAmount(memberGold.getInterestHistoryAmount());
                        memberGold.setPrincipalAmount(BigDecimalUtil.adds(memberGold.getPrincipalNowAmount(), memberGold.getPrincipalHistoryAmount()));
                        memberGold.setUsableAmount(BigDecimalUtil.adds(memberGold.getPrincipalAmount(), memberGold.getInterestAmount()));
                        memberGold.setTotalAmount(BigDecimalUtil.adds(memberGold.getUsableAmount(), memberGold.getFreezeAmount()));
                        memberGold.setTurnOutAmount(BigDecimalUtil.adds(memberGold.getTurnOutAmount(), payAmount[0]));
                        memberGold.setFreezeGram(new BigDecimal(payWeight));
                        int rows = memberGoldMapper.update(memberGold);
                        return new SerializeObject<>(ResultType.NORMAL, "00000001", orderId);
                    } else {
                        return new SerializeObject<>(ResultType.ERROR, resultMap.get("msg").toString(), "");
                    }
                }
            } finally {
                redisGlobalLock.unlock(orderSubmitKey);
            }
        } else {
            return new SerializeObjectError("17000706");
        }
    }

    /**
     * 公共支付请求
     *
     * @param payParamBean
     * @return
     */
    //@Transactional(rollbackFor = Exception.class)
    @Override
    public Map<String, Object> commonPayRequest(PayParamBean payParamBean) {
        //定义返回类型
        Map<String, Object> resultMap = null;
        // 1、获取分布式锁防止重复调用 =====================================================
        String orderSubmitKey = PayDistributePrefix.PAY_ORDER_SUBMIT + payParamBean.getOrderId();
        // 2、获取分布式锁进行对账户锁定 =====================================================
        if (redisGlobalLock.lock(orderSubmitKey, CommonConstants.PAY_ORDER_SUBMIT_LOCK_TIME, TimeUnit.MILLISECONDS)) {
            try {
                LoginBean loginBean = LoginHelper.getLoginBean();
                //根据绑定银行卡获取银行卡相关信息
                BankCard bankCard = bankCardMapper.findDefaultByMemberId(loginBean.getId());
                Ensure.that(bankCard == null).isTrue("17000419");
                payParamBean.setBankCardId(bankCard.getId());
                String title = null;
                BigDecimal amount = null;
                BigDecimal goldPrice = null;
                BigDecimal itemAmount = BigDecimal.ZERO;

                double lowestQuota = 0;
                ProductOrderBean productOrderBean = null;
                ProductFindBean productBean = null;
                PayTbill payTbill = null;
                if (CommonConstants.PayType.BUYING.getIndex() == payParamBean.getType() || CommonConstants.PayType.RECHARGE.getIndex() == payParamBean.getType()) {
                    productOrderBean = productOrderService.findByOrderId(payParamBean.getOrderId());
                    Ensure.that(productOrderBean == null || productOrderBean.getPayStatus() == ProductOrderPayStatus.FAIL.getValue()).isTrue("17000424");
                    SerializeObject<ProductFindBean> productFindBean = productService.queryProductById(productOrderBean.getProductId());
                    if (null == productFindBean || productFindBean.getCode() != ResultType.NORMAL) {
                        Ensure.that(true).isTrue("17000601");
                    }
                    productBean = productFindBean.getData();
                    if (productBean.getType() == 1) {
                        int num = productOrderMapper.countTodayNoviceOrders();
                        if (num >= 1000) {
                            Ensure.that(true).isTrue("17000721");
                        }
                    }
                    if (productBean.getShelfState() == 2) {
                        Ensure.that(true).isTrue("17000720");
                    }
                    if (productBean.getIsOpen() != null && productBean.getIsOpen() == 2) {
                        Ensure.that(true).isTrue("170020456");
                    }
                    int num = productOrderMapper.countActivityOrders(loginBean.getId(), productBean.getId());
                    logger.info(loginBean.getId() + "-----购买活动金次数-----" + num);
                    if (num > 0) {
                        Ensure.that(true).isTrue("17002013");
                    }
                    BigDecimal todayBuyAmount = productOrderMapper.sumToadySuccessAmount(loginBean.getId());
                    if (null == todayBuyAmount) {
                        todayBuyAmount = BigDecimal.ZERO;
                    }
                    todayBuyAmount = BigDecimalUtil.add(todayBuyAmount, productOrderBean.getAmount());
                    SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.BUY_SELL_GRAM.getKey());
                    //if (fundRateConfig.getMaxBuyWeightPerDay().compareTo(todayBuyAmount) < 0) {
                    if (serializeObject.getData()!=null) {
                        Map<String, Object> map = (Map<String, Object>) serializeObject.getData();
                        String maxGramPerday = String.valueOf(map.get(BUY_MAX_GRAM_PERDAY));
                        if (new BigDecimal(maxGramPerday).compareTo(todayBuyAmount) < 0
                                && !"0".equals(maxGramPerday)) {
                            Ensure.that(true).isTrue("17000715");
                        }
                    }

                    if (productBean.getRaiseGram().doubleValue() > 0) {
                        double toRasizeGram = 0;
                        if (productBean.getToRaiseGram() != null) {
                            toRasizeGram = productBean.getToRaiseGram().doubleValue();
                        }
                        SerializeObject<List<DataDictionaryBean>> beans = dataDictionaryService.findListByClassification(GOLD_WEIGHT_RANGE, 1);
                        if (beans == null || beans.getData() == null || beans.getData().size() != 2) {
                            Ensure.that(true).isTrue("17000719");
                        }
                        double value0 = Double.parseDouble(beans.getData().get(0).getItemValue());
                        double value1 = Double.parseDouble(beans.getData().get(1).getItemValue());
                        if (value0 > value1) {
                            double totalGram = productBean.getRaiseGram().doubleValue() * value0 / 100;
                            lowestQuota = productBean.getRaiseGram().doubleValue() * value1 / 100;
                            if ((toRasizeGram + productOrderBean.getAmount().doubleValue()) > totalGram) {
                                productOrderService.updatePayStatus(ProductOrderPayStatus.FAIL.getValue(), productOrderBean.getOrderId());
                                ProductOrderFee productOrderFee = productOrderFeeMapper.findByOrderId(productOrderBean.getOrderId());
                                if (null != productOrderFee) {
                                    if (StringUtils.isNotBlank(productOrderFee.getCouponRedId())) {
                                        couponRepertoryService.unlock(productOrderFee.getCouponRedId());
                                    }
                                    if (StringUtils.isNotBlank(productOrderFee.getCouponIncreaseId())) {
                                        couponRepertoryService.unlock(productOrderFee.getCouponIncreaseId());
                                    }
                                }
                                Ensure.that(true).isTrue("17000719");
                            }
                        } else {
                            double totalGram = productBean.getRaiseGram().doubleValue() * value1 / 100;
                            lowestQuota = productBean.getRaiseGram().doubleValue() * value0 / 100;
                            if ((toRasizeGram + productOrderBean.getAmount().doubleValue()) > totalGram) {
                                productOrderService.updatePayStatus(ProductOrderPayStatus.FAIL.getValue(), productOrderBean.getOrderId());
                                ProductOrderFee productOrderFee = productOrderFeeMapper.findByOrderId(productOrderBean.getOrderId());
                                if (null != productOrderFee) {
                                    if (StringUtils.isNotBlank(productOrderFee.getCouponRedId())) {
                                        couponRepertoryService.unlock(productOrderFee.getCouponRedId());
                                    }
                                    if (StringUtils.isNotBlank(productOrderFee.getCouponIncreaseId())) {
                                        couponRepertoryService.unlock(productOrderFee.getCouponIncreaseId());
                                    }
                                }
                                Ensure.that(true).isTrue("17000719");
                            }
                        }
                    }
                    title = productOrderBean.getProductName();
                    amount = productOrderBean.getActualAmount();
                    itemAmount = productOrderBean.getItemAmount();
                    goldPrice = productOrderBean.getGoldPrice();
                } else if (CommonConstants.PayType.MALL.getIndex() == payParamBean.getType()) {
                    SerializeObject<MemberGoodsOrderDetailBean> mallObj = mallGoodsOrderService.getOrderDetail(payParamBean.getOrderId());
                    if (mallObj.getCode() == ResultType.NORMAL) {
                        MemberGoodsOrderDetailBean goodsOrder = mallObj.getData();
                        title = goodsOrder.getGoodsName();
                        amount = goodsOrder.getActualAmount();
                        itemAmount = goodsOrder.getActualAmount();
                    } else {
                        Ensure.that(true).isTrue("17000416");
                    }
                } else if (PayTypeEnum.MALL_NEW.getType() == payParamBean.getType()) {
                    SerializeObject mallObj = orderService.validateOrder(payParamBean.getOrderId());
                    if (mallObj == null) {
                        Ensure.that(true).isTrue("17000416");
                    }
                    if (mallObj.getCode() == ResultType.NORMAL) {
                        SerializeObject<OrderBean> orderBean = orderService.getOrder(payParamBean.getOrderId());
                        if (orderBean == null || orderBean.getData() == null) {
                            Ensure.that(true).isTrue("00000002");
                        }
                        if (orderBean.getData().getStatus() != null && orderBean.getData().getStatus() == 2) {
                            Ensure.that(true).isTrue("17000424");
                        }
                        amount = orderBean.getData().getMoney();
                        itemAmount = orderBean.getData().getMoney();
                        //等【商品件数】件商品
                        SerializeObject<List<String>> orderNames = orderService.listGoodsNames(payParamBean.getOrderId());
                        if (orderNames != null && orderNames.getData() != null && orderNames.getData().size() > 0) {
                            if (orderNames.getData().size() > 1) {
                                title = orderNames.getData().get(0) + "等" + orderNames.getData().size() + "件商品";
                            } else {
                                title = orderNames.getData().get(0);
                            }
                        }
                    } else {
                        if (resultMap == null) {
                            resultMap = new HashMap<String, Object>();
                        }
                        resultMap.put("msg", mallObj.getMsg());
                        return resultMap;
                    }
                } else if (PayTypeEnum.TBILL.getType() == payParamBean.getType()) {
                    payTbill = payTbillMapper.selectByOrderNO(payParamBean.getOrderId());
                    Ensure.that(payTbill == null || payTbill.getStatus() == TbillStatusEnum.FAIL.getStatus()).isTrue("17000424");
                    SerializeObject<ProductFindBean> productFindBean = productService.queryProductById(payTbill.getProductId());
                    if (null == productFindBean || productFindBean.getCode() != ResultType.NORMAL) {
                        Ensure.that(true).isTrue("17000601");
                    }
                    productBean = productFindBean.getData();
                    if (productBean.getSpecification() == null || productBean.getSpecification() < 1 || productBean.getLeaseDayList() == null || productBean.getLeaseDayList().size() == 0) {
                        Ensure.that(true).isTrue("00000002");
                    }
                    if (productBean.getShelfState() == 2) {
                        Ensure.that(true).isTrue("17000720");
                    }
                    Integer canBuyUserType = productBean.getCanBuyUserType();
                    canBuyUserType = canBuyUserType == null ? 1 : canBuyUserType;
                    if (canBuyUserType == 2) {
                        int successfulNum = payTbillMapper.countSuccessfulNum(payTbill.getMemberId());
                        if (successfulNum == 0) {
                            Ensure.that(true).isTrue("17002043");
                        }
                    } else if (canBuyUserType == 3) {
                        int successfulNum = payTbillMapper.countSuccessfulNum(payTbill.getMemberId());
                        if (successfulNum > 0) {
                            Ensure.that(true).isTrue("17002042");
                        }
                    }
                    Integer userAstrictStatus = productBean.getUserAstrictStatus();
                    userAstrictStatus = userAstrictStatus == null ? 0 : userAstrictStatus;
                    int num = payTbill.getTotalGram() / productBean.getSpecification();
                    if (userAstrictStatus == 1) {
                        int gram = payTbillMapper.sumSuccessfulGram(payTbill.getMemberId(), payTbill.getProductId());
                        Integer userAstrictNum = productBean.getUserAstrictNum();
                        int successfulNum = gram/productBean.getSpecification();
                        userAstrictNum = userAstrictNum == null ? 0 : userAstrictNum;
                        if ((successfulNum + num) > userAstrictNum) {
                            Ensure.that(true).isTrue("17002044", String.valueOf(userAstrictNum));
                        }
                    } else if (userAstrictStatus == 2) {
                        int gram = payTbillMapper.sumSuccessfulGram(payTbill.getMemberId(), payTbill.getProductId());
                        Integer userAstrictGram = productBean.getUserAstrictGram();
                        userAstrictGram = userAstrictGram == null ? 0 : userAstrictGram;
                        if ((gram + payTbill.getTotalGram()) > userAstrictGram) {
                            Ensure.that(true).isTrue("17002045", String.valueOf(userAstrictGram));
                        }
                    }
                    Integer stock = productBean.getStock();
                    stock = stock == null ? 0 : stock;
                    if (num > stock) {
                        Ensure.that(true).isTrue("17002046");
                    }
                    BigDecimal todayBuyGram = new BigDecimal(payTbillMapper.sumToadySuccessGram(loginBean.getId()));
                    todayBuyGram = BigDecimalUtil.add(todayBuyGram, new BigDecimal(payTbill.getTotalGram()));
                    SerializeObject serializeObject = rateSettingsService.get(RateKeyEnum.BUY_SELL_GRAM.getKey());
                    if (serializeObject.getData()!=null) {
                        Map<String, Object> map = (Map<String, Object>) serializeObject.getData();
                        String maxGramPerday = String.valueOf(map.get(BUY_MAX_GRAM_PERDAY));
                        if (new BigDecimal(maxGramPerday).compareTo(todayBuyGram) < 0 && !"0".equals(maxGramPerday)) {
                            Ensure.that(true).isTrue("17000715");
                        }
                    }
                    title = payTbill.getProductName();
                    amount = payTbill.getPayAmount();
                    itemAmount = payTbill.getTotalAmount();
                    goldPrice = payTbill.getGoldPrice();
                }

                //设置参数
                Ensure.that(loginBean == null).isTrue("00000102");
                payParamBean.setMemberId(loginBean.getId());
                payParamBean.setTitle(title);
                payParamBean.setAmount(amount);
                payParamBean.setFee(BigDecimal.ZERO);

                // 1、获取分布式锁防止重复调用 =====================================================
                String key = PayDistributePrefix.PAY_MEMBER_ACCOUNT + loginBean.getId();
                if (redisGlobalLock.lock(key)) {
                    try {
                        //获取账户余额
                        MemberAccount memberAccount = memberAccountMapper.findByMemberId(loginBean.getId());
                        Ensure.that(memberAccount == null).isTrue("00000003");

                        //生成本地交易信息
                        Trade trade = tradeMapper.queryTradeByOrderId(payParamBean.getOrderId());
                        if (trade == null) {
                            trade = Trade.convert(payParamBean);
                            //设置实际支付金额
                            if (memberAccount.getUsableAmount().compareTo(payParamBean.getAmount()) < 0) {
                                BigDecimal payAmount = BigDecimalUtil.to2Point(payParamBean.getAmount().subtract(memberAccount.getUsableAmount()));   //银行卡实际支付金额
                                trade.setPayAmount(payAmount);
                            }
                            BigDecimal fee = BigDecimalUtil.to2Point(amount.subtract(itemAmount));
                            trade.setFee(fee);
                            tradeMapper.insert(trade);
                        }

                        //余额支付
                        if (memberAccount.getUsableAmount().compareTo(payParamBean.getAmount()) >= 0) {
                            BigDecimal fundAmount = BigDecimalUtil.to2Point(memberAccount.getFundAmount().subtract(amount));
                            BigDecimal usableAmount = BigDecimalUtil.to2Point(memberAccount.getUsableAmount().subtract(amount));
                            //扣除账户余额
                            Map<String, Object> param = new HashMap<String, Object>();
                            param.put("id", memberAccount.getId());
                            param.put("fundAmount", fundAmount);
                            param.put("usableAmount", usableAmount);
                            memberAccountMapper.updateByPrimaryKeySelective(param);

                            //更新订单交易记录
                            Trade trades = new Trade();
                            trades.setSerialNumber(payParamBean.getOrderId());
                            trades.setStatus(CommonConstants.PayStatus.YESPAY.getIndex());
                            tradeMapper.updatePayStatus(trades);

                            //支出明细
                            BillBean billBean = cn.ug.pay.utils.Common.getBillBean(trade);
                            billBean.setType(BillType.OUTLAY.getValue());
                            billBean.setTradeType(TradeType.BUY_GOLD.getValue());
                            billBean.setGoldPrice(goldPrice);

                            //更新订单状态
                            if (CommonConstants.PayType.BUYING.getIndex() == payParamBean.getType() || CommonConstants.PayType.RECHARGE.getIndex() == payParamBean.getType()) {
                                productOrderService.completePay(trade.getOrderId());
                                billBean.setTradeType(TradeType.BUY_GOLD.getValue());
                                productService.addToRaiseGram(productBean.getId(), productOrderBean.getAmount());
                                if (productBean.getRaiseGram().doubleValue() > 0) {
                                    double hadRaisedGram = productBean.getToRaiseGram().doubleValue() + productOrderBean.getAmount().doubleValue();
                                    if (hadRaisedGram >= lowestQuota) {
                                        productService.updateShelfState(productBean.getId(), 2);
                                        SerializeObject<List<DataDictionaryBean>> beans = dataDictionaryService.findListByClassification(cn.ug.msg.bean.status.CommonConstants.MsgType.PRODUCT_DOWN_SHELF.getName(), 1);
                                        if (beans != null && beans.getData() != null) {
                                            List<DataDictionaryBean> data = beans.getData();
                                            if (data != null && data.size() > 0) {
                                                for (DataDictionaryBean bean : data) {
                                                    Sms sms = new Sms();
                                                    sms.setPhone(bean.getItemValue());
                                                    sms.setType(SmsType.SOLD_OUT);
                                                    Map<String, String> paramMap = new HashMap<>(2);
                                                    paramMap.put("produtName", productBean.getName());
                                                    paramMap.put("hour", String.valueOf(Calendar.getInstance().get(Calendar.HOUR_OF_DAY)));
                                                    sms.setParamMap(paramMap);
                                                    amqpTemplate.convertAndSend(QUEUE_MSG_SMS_SEND, sms);
                                                }
                                            }
                                        }
                                    }
                                }

                                /**
                                 * 微信服务号消息推送
                                 */
                                WxMessageParamBean wxMessageParamBean = new WxMessageParamBean();
                                wxMessageParamBean.setMemberId(trade.getMemberId());
                                WxNotifyData wxNotifyData = new WxNotifyData();
                                Map<String, WxNotifyData.TemplateDataAttr> wxParamMap = new HashMap();
                                WxNotifyData.TemplateDataAttr first = new WxNotifyData.TemplateDataAttr();
                                //消息推送类型
                                WxTemplateEnum wxTemplateEnum = null;
                                if (productOrderBean.getType() != 3) {
                                    wxMessageParamBean.setType(WxTemplateEnum.PURCHASE_TIMING_PRODUCT_SUCCEED.getType());
                                    wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.PURCHASE_TIMING_PRODUCT_SUCCEED.getType());

                                    first.setDataValue(wxTemplateEnum.getFirstData().replace("{product}", productOrderBean.getProductName()).
                                            replace("{deadline}", productOrderBean.getInvestDay()).replace("{expireTime}", productOrderBean.getEndTimeString()).
                                            replace("{predictEarnings}", BigDecimalUtil.to5Point(productOrderBean.getIncomeAmount()).toString()));
                                } else if (productOrderBean.getType() == 3) {
                                    wxMessageParamBean.setType(WxTemplateEnum.PURCHASE_ACTIVITY_PRODUCT_SUCCEED.getType());
                                    wxTemplateEnum = WxTemplateEnum.getWxTemplateByCode(WxTemplateEnum.PURCHASE_ACTIVITY_PRODUCT_SUCCEED.getType());
                                    first.setDataValue(wxTemplateEnum.getFirstData().replace("{product}", productOrderBean.getProductName()));
                                }

                                wxParamMap.put("first", first);
                                WxNotifyData.TemplateDataAttr keyword1 = new WxNotifyData.TemplateDataAttr();
                                keyword1.setDataValue(payParamBean.getOrderId());
                                wxParamMap.put("keyword1", keyword1);

                                WxNotifyData.TemplateDataAttr keyword2 = new WxNotifyData.TemplateDataAttr();
                                keyword2.setDataValue(BigDecimalUtil.to5Point(productOrderBean.getAmount()).toString());
                                wxParamMap.put("keyword2", keyword2);

                                WxNotifyData.TemplateDataAttr keyword3 = new WxNotifyData.TemplateDataAttr();
                                keyword3.setDataValue(BigDecimalUtil.to2Point(payParamBean.getAmount()).toString());
                                wxParamMap.put("keyword3", keyword3);

                                WxNotifyData.TemplateDataAttr keyword4 = new WxNotifyData.TemplateDataAttr();
                                keyword4.setDataValue(BigDecimalUtil.to2Point(goldPrice).toString());
                                wxParamMap.put("keyword4", keyword4);

                                WxNotifyData.TemplateDataAttr keyword5 = new WxNotifyData.TemplateDataAttr();
                                keyword5.setDataValue(DateUtils.dateToStr(new Date(), DateUtils.patter));
                                wxParamMap.put("keyword5", keyword5);

                                WxNotifyData.TemplateDataAttr remark = new WxNotifyData.TemplateDataAttr();
                                remark.setDataValue(wxTemplateEnum.getRemark());
                                wxParamMap.put("remark", remark);

                                wxNotifyData.setData(wxParamMap);
                                wxMessageParamBean.setTemplateData(wxNotifyData);
                                amqpTemplate.convertAndSend(QUEUE_MSG_WX_SEND, wxMessageParamBean);
                            } else if (CommonConstants.PayType.MALL.getIndex() == payParamBean.getType()) {
                                mallGoodsOrderService.succeedOrder(trade.getOrderId());
                                billBean.setTradeType(TradeType.BUY_GOODS.getValue());
                            } else if (PayTypeEnum.MALL_NEW.getType() == payParamBean.getType()) {
                                orderService.succeed(trade.getOrderId());
                                billBean.setTradeType(TradeType.BUY_GOODS.getValue());
                                Msg msg = new Msg();
                                msg.setMemberId(trade.getMemberId());
                                msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.MALL_PAY_SUCCESS.getIndex());
                                Map<String, String> paramMap = new HashMap<>();
                                paramMap.put("goodsName", trade.getTitle());
                                paramMap.put("fundAmount", fundAmount.toString());
                                msg.setParamMap(paramMap);
                                amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
                            } else if (PayTypeEnum.TBILL.getType() == payParamBean.getType()) {
                                payTbillService.completePay(trade.getOrderId());
                                billBean.setTradeType(TradeType.BUY_GOLD.getValue());
                                billBean.setGoldPrice(payTbill.getGoldPrice());
                                int stock = productBean.getStock() - payTbill.getTotalGram()/productBean.getSpecification();
                                productService.updateStock(payTbill.getProductId(), stock);
                            }

                            //更新支出明细
                            billService.save(billBean);

                            //增加账户余额变动消息队列
                            payCommon.accountChangeMsgQueue(loginBean.getId(), cn.ug.msg.bean.status.CommonConstants.MsgType.ACCOUNT_PAY_CHANGE.getIndex(),
                                    BigDecimalUtil.to2Point(payParamBean.getAmount()).toString(), fundAmount.toString());
                            //余额+现金支付
                        } else {
                            //验证银行是否维护中
                            BankInfoBean bankInfo = bankInfoMapper.queryBankInfo(bankCard.getBankCode());
                            if (bankInfo != null && CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()) {
                                Msg msg = new Msg();
                                msg.setMemberId(trade.getMemberId());
                                msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.BANK_MAINTENANCE.getIndex());
                                Map<String, String> paramMap = new HashMap<>();
                                paramMap.put("bankName", cn.ug.util.StringUtils.sensitivityBankCard(bankCard.getCardNo()));
                                msg.setParamMap(paramMap);
                                amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
                                Ensure.that(CommonConstants.CardStatus.MAINTENANCE.getIndex() == bankInfo.getStatus()).isTrue("17000423");
                            }

                            SerializeObject rateBean  = rateSettingsService.get(RateKeyEnum.RECHARGE.getKey());
                            BigDecimal fee = BigDecimal.ZERO;
                            if (rateBean != null && rateBean.getData() != null) {
                                JSONObject json = JSON.parseObject(JSONObject.toJSONString(rateBean.getData()));
                                int dayNum = billMapper.getTransactionNumForThisDay(loginBean.getId(), CommonConstants.PayType.RECHARGE.getIndex());
                                int monthNum = billMapper.getTransactionNumForThisMonth(loginBean.getId(), CommonConstants.PayType.RECHARGE.getIndex());
                                fee = fundRateConfig.getFee(json, itemAmount.subtract(memberAccount.getUsableAmount()), dayNum, monthNum);
                            }
                            amount = BigDecimalUtil.to2Point(amount.add(fee));
                            //设置付款金额
                            payParamBean.setAmount(BigDecimalUtil.to2Point(amount.subtract(memberAccount.getUsableAmount())));

                            //设置公共类
                            BankCardBean bankCardBean = dozerBeanMapper.map(bankCard, BankCardBean.class);
                            TradeCommonParamBean entity = dozerBeanMapper.map(payParamBean, TradeCommonParamBean.class);
                            entity.setBankCardBean(bankCardBean);
                            entity.setPayAmount(BigDecimalUtil.to2Point(amount));
                            entity.setType(payParamBean.getType());
                            //选择支付方式
                            switch (payParamBean.getWay()) {
                                case TradeStatus.PayWay.yeePay:
                                    resultMap = yeePayCommons.prepayOrder(entity);
                                    break;
                            }
                        }
                    } catch (Exception e) {
                        logger.error("---支付捕获异常成功--", e);
                        throw e;
                    } finally {
                        // 4、释放分布式锁 ================================================================
                        redisGlobalLock.unlock(key);
                    }
                } else {
                    // 如果没有获取锁
                    Ensure.that(true).isTrue("17000706");
                }
            } catch (Exception e) {
                logger.error("---重复提交捕获异常成功--", e);
                throw e;
            } finally {
                // 4、释放分布式锁 ================================================================
                redisGlobalLock.unlock(orderSubmitKey);
            }
        } else {
            // 如果没有获取锁
            logger.info("-------没有获取到锁-------");
            Ensure.that(true).isTrue("17000706");
        }
        return resultMap;
    }

    /**
     * 公共支付异步回调
     *
     * @param yeePayParamBean
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public String yeePayAsyNotify(YeePayParamBean yeePayParamBean) {
        logger.info("merchantno=" + yeePayParamBean.getMerchantno() + ",key=" + yeePayParamBean.getEncryptkey() + ",data" + yeePayParamBean.getData());
        return yeePayCommons.yeePayAsyNotify(yeePayParamBean);
    }

    /**
     * 提现请求
     *
     * @param withdrawMQ
     * @return
     */
    @Transactional
    @Override
    public String yeePayWithdraw(WithdrawMQ withdrawMQ) {

        //验证重复发起请求
        WithdrawAuditBean withdrawAuditBean = withdrawService.findByOrderId(withdrawMQ.getOrderId());
        Ensure.that(withdrawAuditBean.getStatus() == WithdrawStatus.PROCESSING.getValue()
                || withdrawAuditBean.getStatus() == WithdrawStatus.SUCCESS.getValue()
                || withdrawAuditBean.getStatus() == WithdrawStatus.FAIL.getValue()).isTrue("");   //验证是否已经发起提现、成功、失败

        //根据会员Id获取绑卡信息
        BankCard bankCard = bankCardMapper.findById(withdrawMQ.getBankCardId());
        Ensure.that(bankCard == null).isTrue("17000410");
        Ensure.that(CommonConstants.BankCardStatus.YES_BIND.getIndex() == bankCard.getStatus()).isFalse("17000410");  //验证该银行卡以否已绑定

        //组装
        BankCardBean bankCardBean = dozerBeanMapper.map(bankCard, BankCardBean.class);
        TradeCommonParamBean paramBean = new TradeCommonParamBean();
        paramBean.setOrderId(withdrawMQ.getOrderId());
        paramBean.setAmount(withdrawMQ.getAmount());
        paramBean.setBankCardBean(bankCardBean);
        TreeMap<String, String> dataMap = getWithdrawRequestParam(paramBean);
        logger.info(dataMap.toString());


        //发起请求
        Map<String, String> map = requestUtil.sendYeePayHttp(yeePayConfig.getWithdrawURL(), dataMap);
        if (map != null && !map.isEmpty()) {
            if (map.containsKey("status")) {
                String status = String.valueOf(map.get("status"));
                //处理中
                if ("PROCESSING".equals(status)) {
                    logger.info("---提现处理中---订单号=" + withdrawMQ.getOrderId());
                    withdrawService.updateStatus(withdrawMQ.getOrderId(), WithdrawStatus.PROCESSING.getValue(), null);

                    //发送短信、站内信--消息队列
                    //提现提醒
                    /*Msg msg = new Msg();
                    msg.setMemberId(withdrawMQ.getMemberId());
                    msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.WITHDRAW.getIndex());

                    Map<String, String> paramMap = new HashMap<>();
                    paramMap.put("amount", withdrawAuditBean.getAmount().toString());
                    msg.setParamMap(paramMap);

                    amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);*/
                } else if ("WITHDRAW_FAIL".equals(status)) {
                    memberAccountService.withdrawFail(withdrawAuditBean.getMemberId(), withdrawAuditBean.getAmount(), withdrawAuditBean.getActualAmount());
                    billMapper.updateTradeTypeByOrderId(withdrawMQ.getOrderId(), TradeType.ACCOUNT_WITHDRWAL_RETURN.getValue(), BillType.INCOME.getValue());
                    logger.info("---提现失败----订单号=" + withdrawMQ.getOrderId() + "-----errormsg" + map.get("errormsg"));
                    withdrawService.updateStatus(withdrawMQ.getOrderId(), WithdrawStatus.FAIL.getValue(), map.get("errormsg"));

                }
            } else {
                //提示错误原因
                Ensure.that(true).isTrue(map.get("customError"));
            }
        }
        return null;
    }

    /**
     * 提现异步回调
     *
     * @param yeePayParamBean
     * @return
     */
    @Transactional
    @Override
    public String yeePayWithdrawAsyNotify(YeePayParamBean yeePayParamBean) {
        return yeePayCommons.yeePayWithdrawAsyNotify(yeePayParamBean);
    }

    @Transactional
    @Override
    public String withdrawZeroMoney(String memberId, String orderId, BigDecimal amount) {
        logger.info("---提现0元开始处理---订单号=" + orderId);
        WithdrawAuditBean withdrawAuditBean = withdrawService.findByOrderId(orderId);
        //将总金额和冻结金额扣除提现金额
        memberAccountService.withdrawSuccess(withdrawAuditBean.getMemberId(), withdrawAuditBean.getAmount());
        withdrawService.updateStatus(orderId, WithdrawStatus.SUCCESS.getValue(), null);
        logger.info("---提现成功---订单号=" + orderId);

        billMapper.updateTradeTypeByOrderId(orderId, TradeType.ACCOUNT_WITHDRAWAL.getValue(), BillType.OUTLAY.getValue());
        //更新支出明细
        //更新明细
        /*BillBean billBean = new BillBean();
        billBean.setOrderId(orderId);
        billBean.setMemberId(withdrawAuditBean.getMemberId());
        billBean.setAmount(withdrawAuditBean.getAmount());
        billBean.setActualAmount(withdrawAuditBean.getActualAmount());
        billBean.setFee(withdrawAuditBean.getFee());
        billBean.setType(BillType.OUTLAY.getValue());
        billBean.setTradeType(TradeType.ACCOUNT_WITHDRAWAL.getValue());
        billService.save(billBean);*/


        Msg msg = new Msg();
        msg.setType(cn.ug.msg.bean.status.CommonConstants.MsgType.WITHDRAW_SUCCESS.getIndex());
        //发送短信、站内信--消息队列
        //提现成功或失败提醒
        msg.setMemberId(withdrawAuditBean.getMemberId());
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("date", UF.getFormatDate("MM月dd日", UF.getDateTime()));
        msg.setParamMap(paramMap);
        //消息队列发送
        amqpTemplate.convertAndSend(QUEUE_MSG_SEND, msg);
        logger.info("------提现0元成功，消息队列已发送--------");
        return null;
    }

    @Override
    public Map<String, String> queryOrderStatus(String orderId) {
        Ensure.that(orderId).isNull("17000413");
        //设置默认返回参数
        Map<String, String> resultMap = new HashMap<String, String>();
        resultMap.put("status", "1");
        //设置时间
        LocalDateTime time = LocalDateTime.now();
        int startTime = time.getSecond();
        ; //开始时间
        int endTime = startTime + 10;  //结束时间为10s
        while (true) {
            try {
                Trade trade = tradeMapper.queryTradeByOrderId(orderId);
                Ensure.that(trade == null).isTrue("17000418");
                if (trade.getStatus() != CommonConstants.PayStatus.PROCESSING.getIndex()) {
                    //组装参数
                    resultMap.put("status", trade.getStatus() + "");
                    resultMap.put("errorMsg", trade.getDescription());
                    //TZ2010073,TZ2010074错误码对应的描述太长进行阻隔处理
                    if("TZ2010073".equalsIgnoreCase(trade.getErrCode()) || "TZ2010074".equalsIgnoreCase(trade.getErrCode())){
                        resultMap.put("errorMsg", "操作失败");
                    }
                    //TZ2010055，TZ2010027 都是余额不足
                    resultMap.put("errorcode",trade.getErrCode());
                    break;
                } else {
                    Thread.sleep(1000);  //每次请求后休息一秒
                }
                //如果请求时间超过10s立马跳出循环
                int currentTime = LocalDateTime.now().getSecond();
                if (currentTime > endTime) {
                    logger.info("--------本次请求时间超过10s--------");
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return resultMap;
    }

    @Override
    public void test() {
        WithdrawMQ mq = new WithdrawMQ();
        yeePayWithdraw(mq);
    }


    /**
     * 提现请求数据组装
     *
     * @param paramBean 交易参数
     * @return
     */
    public TreeMap<String, String> getWithdrawRequestParam(TradeCommonParamBean paramBean) {
        TreeMap<String, String> dataMap = new TreeMap<String, String>();
        dataMap.put("merchantno", yeePayConfig.getMerchantAccount());
        dataMap.put("requestno", paramBean.getOrderId());
        dataMap.put("identityid", paramBean.getBankCardBean().getRequestNo());
        dataMap.put("identitytype", CommonConstants.USER_ID);
        dataMap.put("amount", paramBean.getAmount().toString());
        dataMap.put("cardtop", paramBean.getBankCardBean().getCardTop());
        dataMap.put("cardlast", paramBean.getBankCardBean().getCardLast());
        dataMap.put("currency", CommonConstants.CURRENCY);
        dataMap.put("drawtype", CommonConstants.DRAWTYPE);
        dataMap.put("userip", CommonConstants.USER_IP);
        dataMap.put("callbackurl", yeePayConfig.getWithdrawCallBackUrl());
        dataMap.put("requesttime", UF.getFormatDateTime(LocalDateTime.now()));
        dataMap.put("sign", tZTService.getSign(dataMap));
        return dataMap;
    }

    public static void main(String[] args) {

       /* LocalDateTime time = LocalDateTime.now();
        int startTime = time.getSecond();; //开始时间
        int endTime = startTime + 10;  //结束时间为10s
        while (startTime <= endTime){
            System.out.println("----------------"+startTime);
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            startTime = time.getSecond();
        }*/

      /* BigDecimal dt1 = new BigDecimal("0.001");
        System.out.println(dt1.compareTo(BigDecimal.ZERO));
        System.out.println(BigDecimalUtil.isZeroOrNull(dt1));*/
    }
}
